package com.lagou.edu.context;


import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.anno.Autowired;
import com.lagou.edu.anno.Bean;
import com.lagou.edu.anno.Service;
import com.lagou.edu.anno.Transaction;
import com.lagou.edu.factory.ProxyFactory;
import com.lagou.edu.reader.BeanReader;
import org.dom4j.DocumentException;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;

public class ApplicationContext {
    private String configPath;
    private HashMap<String, Object> beans = null;

    public ApplicationContext(String configPath) throws Exception {
        this.configPath = configPath;
        beans = new HashMap<String, Object>();
        // 初始化beans Service注解
        initBeans();
        // 初始化属性 及 Autowired注解
        initAttribute();
    }

    private void initAttribute() throws Exception {
        for (Object o : beans.keySet()) {
            // 依赖注入
            attriAssign(beans.get(o));
        }
    }

    // 初始化对象
    public void initBeans() throws IllegalArgumentException, IllegalAccessException, ClassNotFoundException, DocumentException {
        // 1.扫包
        List<Class<?>> classes = BeanReader.reader(configPath);
        // 2.判断是否有注解
        HashMap<String, Object> findClassExisAnnotation = ExisAnnotation(classes);
        if (findClassExisAnnotation == null || findClassExisAnnotation.isEmpty()) {
            throw new RuntimeException("没有注解");
        }
    }

    public Object getBean(String beanId) throws Exception {
        Object class1;
        if (beanId == null || StringUtils.isEmpty(beanId)) {
            throw new RuntimeException("beanId不能为空");
        }
         class1 = beans.get(beanId);
        //获取到bean 判断是否有@transaction注解

        if (class1 == null) {
            //如果是空 就试着创建bean
            Class<?> aClass = Class.forName(beanId);
            if (aClass == null) {
                throw new RuntimeException("错误类");
            }
            class1 = aClass.newInstance();
        }
        Transaction annotation = class1.getClass().getAnnotation(Transaction.class);
        if(annotation!=null){
            ProxyFactory proxyFactory = (ProxyFactory) beans.get("proxyFactory");
            //如果有实现接口 就用jdk代理 否则 就用cglib
            if ( class1.getClass().getInterfaces().length>0){
                return proxyFactory.getJdkProxy(class1);
            }else {
                return proxyFactory.getCglibProxy(class1);
            }

        }
        return class1;
    }

    // 是否有注解
    public HashMap<String, Object> ExisAnnotation(List<Class<?>> classes)
            throws IllegalArgumentException, IllegalAccessException {
        String beanId;
        for (Class<?> class1 : classes) {
            Service annotation = class1.getAnnotation(Service.class);
            Bean dao = class1.getAnnotation(Bean.class);
            if (annotation != null || dao != null) {
                // beanid 类名小写
                if (annotation==null){
                    beanId = dao.value();
                }else {
                    beanId = annotation.value();
                }

                if (StringUtils.isEmpty(beanId)) {
                    beanId = toLowerCaseFirstOne(class1.getSimpleName());
                }

                //实例化当前bean
                Object newInstance = newInstance(class1);
                //放入map
                beans.put(beanId, newInstance);
            }
        }
        return beans;
    }

    // 首字母转小写
    public static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }

    // 通过反射生成对象
    public Object newInstance(Class<?> classInfo) {
        try {
            return classInfo.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("反射生成对象失败" + e.getMessage());
        }
    }

    // 依赖注入实现原理
    public void attriAssign(Object object) throws Exception {
        // 1.使用反射机制获取当前类的所有属性
        Field[] declaredFields = object.getClass().getDeclaredFields();
        // 2.判断当前类是否存在注解
        for (Field field : declaredFields) {
            Autowired annotation = field.getAnnotation(Autowired.class);
            if (annotation != null) {
                // 获取属性名称
                String name = field.getName();
                // 根据beanName查找对象
                Object newBean = getBean(name);
                // 3.默认使用属性名称,查找bean容器对象
                if (object != null) {
                    //暴力访问
                    field.setAccessible(true);
                    // 给属性赋值 将对象注入到 属性中
                    field.set(object, newBean);
                }
            }
        }
    }
}

